package com.yilin.xbr.core.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * 创 建 人： yangjiaqiao 日 期： 2016年5月5日 下午3:18:49 修 改 人： 日 期： 描 述： 版 本 号： V1.0
 */
public class JsonUtil {

    //序列化对象转JSON字符串jackson
    public static <T> String serializeToJson(T object) {
        ObjectMapper mapper=new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        String json = null;
        try {
            json = mapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return json;
    }

    public static <T> T serializeToObject(String jsonStr, TypeReference<T> typeToken) {
        ObjectMapper mapper=new ObjectMapper();
        //忽略实体类中不存在的字段
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        T obj= null;
        try {
            obj = mapper.readValue(jsonStr, typeToken);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return obj;
    }

    public static<T> T mapToEntity(Map<String, Object> info, TypeReference<T> typeToken) {
        ObjectMapper mapper=new ObjectMapper();
        T obj= null;
        try {
            String jsonStr = mapper.writeValueAsString(info);
            obj = mapper.readValue(jsonStr, typeToken);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return obj;
    }

    //JSON字符串转对象  根据TypeToken类型
    public static <T> T jsonToObject(String jsonStr, TypeToken<T> typeToken) {
        if (jsonStr==null){
            return null;
        }
        return (T) getGson().fromJson(jsonStr, typeToken.getType());
    }

    //对象转JSON字符串
    public static <T> String objectToJson(T object) {
        if (object==null) return null;
        return getGson().toJson(object);
    }


    public static Gson getGson() {
        return getBuilder().create();
    }

    static GsonBuilder builder;

    public static GsonBuilder getBuilder() {
        if (builder == null) {
            builder = new GsonBuilder().registerTypeAdapterFactory(new TypeAdapterFactory() {
                @Override
                public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> typeToken) {
                    Class rawType = typeToken.getRawType();
                    try {
                        if (rawType.isEnum()) {
                            Method valuesMethod = null;
                            valuesMethod = rawType.getMethod("values");
                            final Object[] enumArray = (Object[]) valuesMethod.invoke(null);
                            TypeAdapter adapter = new TypeAdapter<T>() {
                                @Override
                                public void write(JsonWriter jsonWriter, T t) throws IOException {
                                    try {
                                        if (t != null) {
                                            Integer value = (Integer) t.getClass().getMethod("ordinal").invoke(t);
                                            jsonWriter.jsonValue(value + "");
                                        } else {
                                            jsonWriter.jsonValue(null);
                                        }
                                    } catch (IllegalAccessException e) {
                                        e.printStackTrace();
                                    } catch (InvocationTargetException e) {
                                        e.printStackTrace();
                                    } catch (NoSuchMethodException e) {
                                        e.printStackTrace();
                                    }
                                }

                                @Override
                                public T read(JsonReader jsonReader) throws IOException {
                                    JsonToken token = jsonReader.peek();
                                    switch (token) {
                                        case NUMBER: //改写数字的处理逻辑，将数字值分为整型与浮点型。
                                            return (T) typeToken.getRawType().cast(enumArray[jsonReader.nextInt()]);
                                        case STRING:
                                            for (Object info : enumArray) {
                                                try {
                                                    String name = (String) info.getClass().getMethod("name").invoke(info);
                                                    String enumName = jsonReader.nextString();
                                                    if (name.equalsIgnoreCase(enumName)) {
                                                        return (T) typeToken.getRawType().cast(info);
                                                    }
                                                } catch (Exception e) {
                                                    e.printStackTrace();
                                                }
                                            }
                                        default:
                                            return null;
                                    }
                                }
                            };
                            return adapter;
                        }
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                    return null;
                }
            }).setDateFormat("yyyy-MM-dd HH:mm:ss");
        }
        return builder;
    }

}
